/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "module_common_core.h"

#include <stddef.h>

#include <securec.h>

#include "card_channel.h"
#include "logger.h"
#include "module_common_core_inner.h"

enum {
    INS_SE_COMMON_CONF = 0x30,
};

#define SE_COMMON_CMD_TRY_TIMES 1

ResultCode SeCommonIsServiceAvailable(CardChannel *channel, ServiceId sid, SeServiceStatus *status)
{
    if (channel == NULL || status == NULL) {
        LOG_ERROR("invalid input");
        return INVALID_PARA_NULL_PTR;
    }

    (void)memset_s(status, sizeof(SeServiceStatus), 0, sizeof(SeServiceStatus));

    ResultCode result = ChannelOpenChannel(channel);
    if (result != SUCCESS) {
        LOG_ERROR("ChannelOpenChannel for sid 0x%x failed = 0x%x", sid, result);
        return result;
    }
    uint8_t response[SE_APP_SELECT_MAX_RSP_LENGTH] = {0};
    uint32_t length = SE_APP_SELECT_MAX_RSP_LENGTH;

    result = ChannelGetOpenChannelResponse(channel, response, &length);
    if (result != SUCCESS) {
        LOG_ERROR("ChannelGetOpenChannelResponse for sid 0x%x failed = 0x%x", sid, result);
        (void)ChannelCloseChannel(channel);
        return result;
    }
    (void)ChannelCloseChannel(channel);

    result = SeServiceStatusFromRspApdu(response, length, status);
    LOG_INFO("sid is 0x%x, ret is %u, ava is %u, version is 0x%x, verndor is 0x%x", (uint32_t)sid, result,
        status->available, status->version, status->config.vendor);
    return result;
}

ResultCode SeCommonSetServiceConfiguration(CardChannel *channel, ServiceId sid, uint32_t lock,
    const SeServiceConfig *config)
{
    if (channel == NULL || config == NULL) {
        LOG_ERROR("invalid input");
        return INVALID_PARA_NULL_PTR;
    }

    ApduCommandHeader header = {CLA_DEFAULT, INS_SE_COMMON_CONF, 0x00, lock ? FLAG_LOCK : FLAG_NO_LOCK};

    CommandApdu *cmd = CreateCommandApdu(&header, (const uint8_t *)config, sizeof(SeServiceConfig), MAX_APDU_RESP_SIZE);
    if (cmd == NULL) {
        LOG_ERROR("CreateCommandApdu failed");
        return CMD_APDU_CREATE_ERR;
    }

    ResponseApdu *rsp = NULL;
    ResultCode result =
        ChannelOpenTransmitCloseWithRetry(channel, SE_COMMON_CMD_TRY_TIMES, DefaultResponseChecker, cmd, &rsp);

    LOG_INFO("sid is 0x%x, ret is %u, lock is %u", (uint32_t)sid, result, lock);
    DestroyCommandApdu(cmd);
    DestroyResponseApdu(rsp);
    return result;
}
